<?php

declare(strict_types=1);

namespace App\User\Service;

use App\Common\Constants\ErrorCode;
use App\Common\Service\BaseService;
use App\User\Model\UserModel;
use Donjan\Permission\Models\Permission;
use Donjan\Permission\Models\Role;
use Exception;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Context;

class PermissionService extends BaseService
{
    /**
     * @Inject
     * @var Role
     */
    protected $role;

    /**
     * @Inject
     * @var Permission
     */
    protected $permission;

    /**
     * @Inject
     * @var UserModel
     */
    protected $user;


    /**
     * @param array $where
     * @param int $type
     * @param array|string[] $field
     * @param int $perPage
     *
     * @return array
     */
    public function getList(array $where, int $type, array $field = ['*'], int $perPage = 200)
    {
        switch ($type) {
            case 1:
                $query = $this->role::query();
                !empty($where['name']) && $query->whereRaw('INSTR(name, ?) > 0', [$where['name']]);
                break;
            case 2:
                $query = $this->permission::query();
                !empty($where['display_name']) && $query->where('display_name', 'like', '%' . $where['display_name'] . '%');
                break;
        }
        $list = $query->select($field)->orderBy('sort', 'asc')->get();
        if (!$list) {
            return ['code' => ErrorCode::NOT_EXIST];
        }
        if ($type == 2) {
            $listArr = $list->toArray();
            $list = $this->generateTree($listArr, 'parent_id');
        }

        return ['code' => ErrorCode::SUCCESS, 'data' => $list];
    }

    /**
     * @param int $id
     * @param int $type
     *
     * @return array
     */
    public function getInfoById(int $id, int $type)
    {
        switch ($type) {
            case 1:
                $query = $this->role::query();
                break;
            case 2:
                $query = $this->permission::query();
                break;
        }
        $res = $query->where('id', $id)->first();
//        if ($res == 1) {
//            $permissionArr = $res->getAllPermissions()->toArray();
//            $ids = implode(',', array_column($permissionArr, 'id'));
//            $res->permissionList = $ids;
//        }

        if ($res) {
            return ['code' => ErrorCode::SUCCESS, 'data' => $res];
        }
        return ['code' => ErrorCode::NOT_EXIST];
    }

    /**
     * @param array $params
     * @param int $type 1角色，2权限
     *
     * @return array
     */
    public function add(array $params, int $type)
    {
        switch ($type) {
            case 1:
                try {
                    DB::transaction(function () use ($params, $type) {
                        $res = Role::create([
                            'name' => $params['name'],
                            'description' => $params['description'],
                            'guard_name' => $params['guard_name'],
                            'tree_id' => isset($params['tree_id']) ? $params['tree_id'] : '',
                        ]);
                        if ($params['permission_id']) {
                            $res2 = $this->handRoleOrPermission((int)$res->id, $params['permission_id'], 1);
                            if ($res2['code']) {
                                throw new \Exception('', ErrorCode::NOT_IN_FORCE);
                            }
                        }
                        Context::set('roleId', $res -> id);
                    });
                    $roleId = Context::get('roleId');
                    return ['code' => ErrorCode::SUCCESS, 'data' => [], 'info' => ['target_id' => $roleId]];
                } catch (Exception $e) {
                    return ['code' => ErrorCode::NOT_IN_FORCE];
                }
                break;
            case 2:
                $res = Permission::create($params);
                break;
        }
        if ($res) {
            return ['code' => ErrorCode::SUCCESS, 'data' => $res, 'info' => ['target_id' => $res -> id]];
        }
        return ['code' => ErrorCode::NOT_IN_FORCE];
    }

    /**
     * @param array $params
     * @param int $type
     * @param string $permissionId
     *
     * @return array
     */
    public function update(array $params, int $type, string $permissionId)
    {
        switch ($type) {
            case 1:
                try {
                    DB::transaction(function () use ($params, $type, $permissionId) {
                        $role = Role::query()->where(['id' => $params['id']])->first();
                        if (empty($role)) {
                            return ['code' => ErrorCode::NOT_EXIST];
                        }
                        Role::where(['id' => $params['id']])->update([
                            'name' => $params['name'],
                            'description' => $params['description'],
                            'guard_name' => $params['guard_name'],
                            'tree_id' => isset($params['tree_id']) ? $params['tree_id'] : '',
                        ]);
                        if ($permissionId) {
                            $additionIdArr = explode(',', $permissionId);
                            for ($i = 0; $i < count($additionIdArr); $i++) {
                                $arr[$i] = intval($additionIdArr[$i]);
                            }
                            $role->syncPermissions($arr);
                        }
                    });
                    return ['code' => ErrorCode::SUCCESS, 'data' => [], 'info' => ['target_id' => $params['id']]];
                } catch (Exception $e) {
                    return ['code' => ErrorCode::NOT_IN_FORCE];
                }
                break;
            case 2:
                $query = $this->permission::query();
                break;
        }

        $res = $query->where(['id' => $params['id']])->update($params);
        if ($res) {
            return ['code' => ErrorCode::SUCCESS, 'data' => $res, 'info' => ['target_id' => $params['id']]];
        }
        return ['code' => ErrorCode::NOT_IN_FORCE];
    }


    /**
     * @param int $id
     * @param int $type     1.角色操作，2.权限节点操作
     *
     * @return mixed
     */
    public function delete(int $id, int $type)
    {
        switch ($type) {
            case 1:
                $query = $this->role::query();
                $find = 'users';
                break;
            case 2:
                $query = $this->permission::query();
                $find = 'roles';
                break;
        }
        $exist = $query->where('id', $id)->first();
        if (!$exist) {
            return ['code' => ErrorCode::NOT_EXIST];
        }
        // 角色被用户使用中，节点被角色使用中的不能被删除
        $hasLow = $exist->$find->toArray();
        if (count($hasLow) > 0) {
            return ['code' => ErrorCode::DELETE_REFUSE];
        }
        $res = $exist->delete();

        if ($res) {
            return ['code' => ErrorCode::SUCCESS, 'data' => $res, 'info' => ['target_id' => $id]];
        }
        return ['code' => ErrorCode::NOT_IN_FORCE];
    }

    /**
     * @param int $aimId
     * @param string $additionId
     * @param int $type
     *
     * @return array
     */
    public function handRoleOrPermission(int $aimId, string $additionId, int $type)
    {
        switch ($type) {
            case 1:
                $query = $this->role::query();
                $handle = 'syncPermissions';
                break;
            case 2:
                $query = $this->user::query();
                $handle = 'syncRoles';
                break;
        }
        $exist = $query->where(['id' => $aimId])->first();
        if (!$exist) {
            return ['code' => ErrorCode::NOT_EXIST];
        }

        $additionIdArr = explode(',', $additionId);
        for ($i = 0; $i < count($additionIdArr); $i++) {
            $arr[$i] = intval($additionIdArr[$i]);
        }
        try {
            $exist->$handle($arr);
        } catch (Exception $e) {
            return ['code' => ErrorCode::NOT_IN_FORCE];
        }

        return ['code' => ErrorCode::SUCCESS, 'data' => []];
    }

    /**
     * @param int $userId
     *
     * @return array
     */
    public function permissionList(int $userId)
    {
        if (!$userId) {
            $userId = $this->jwt->getParserData()['uid'];
        }
        $user = $this->user->where(['id' => $userId])->first();
        if (!$user) {
            return ['code' => ErrorCode::NOT_EXIST];
        }
        $list = $user->getMenu();
        return ['code' => ErrorCode::SUCCESS, 'data' => $list];
    }

}
